﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
using System.Collections;
using ViewMaker.Core.ViewModels;
using ViewMaker.Core.Utils;
using System.Windows.Media;
using System.Windows.Input;

namespace ViewMaker.Core.Controls
{
    /// <summary>
    /// ViewControl FrameworkElementレベル
    /// </summary>
    public abstract class ViewControl : ViewElement, IItemPropProvider
    {
        public new  class Properties : ViewElement.Properties
        {
            public const string Width = "Width";
            public const string Height = "Height";

            public const string VerticalAlignment = "VerticalAlignment";
            public const string HorizontalAlignment = "HorizontalAlignment";
            public const string CanvasLeft = "CanvasLeft";
            public const string CanvasTop = "CanvasTop";
            public const string GridHeight = "GridHeight";
            public const string GridWidth = "GridWidth";
            public const string RowSpan = "RowSpan";
            public const string ColumnSpan = "ColumnSpan";

            public const string IsEnabled = "IsEnabled";
            public const string IsVisibile = "IsVisibile";

            public const string FontSize = "FontSize";
            public const string Foreground = "Foreground";
            public const string Background = "Background";

            public const string WindowWidth = "Window.Width";
            public const string WindowHeight = "Window.Height";
            public const string WindowMargin = "Window.Margin";
            public const string WindowResizeMode = "Window.ResizeMode";
            public const string WindowState = "Window.State";
            public const string WindowFontSize = "Window.FontSize";
            public const string WindowForeground = "Window.Foreground";
            public const string WindowBackground = "Window.Background";
            public const string WindowClosingCommand = "Window.ClosingCommand";

        }

        #region プロパティ

        /// <summary>
        /// コントロール幅
        /// </summary>
        [Display(GroupName = LayoutGroup)]
        public int? Width
        {
            get { return _width; }
            set { if (_width != value) { _width = value; OnPropertyChanged("Width"); } }
        }
        private int? _width;

        /// <summary>
        /// コントロール高さ
        /// </summary>
        [Display(GroupName = LayoutGroup)]
        public int? Height
        {
            get { return _height; }
            set { if (_height != value) { _height = value; OnPropertyChanged("Height"); } }
        }
        private int? _height;

        /// <summary>
        /// キャンバスへの配置左位置
        /// </summary>
        [Display(Name = "Canvas Left", GroupName=LayoutGroup)]
        [ViewProperty(ViewControl.Properties.IsVisibile, "IsCanvasElement")]
        public int? CanvasLeft
        {
            get { return _canvasLeft; }
            set { _canvasLeft = value; OnPropertyChanged("CanvasLeft"); }
        }
        private int? _canvasLeft;

        /// <summary>
        /// キャンバスへの配置上位置
        /// </summary>
        [Display(Name = "Canvas Top", GroupName = LayoutGroup)]
        [ViewProperty(ViewControl.Properties.IsVisibile, "IsCanvasElement")]
        public int? CanvasTop
        {
            get { return _canvasTop; }
            set { _canvasTop = value; OnPropertyChanged("CanvasTop"); }
        }
        private int? _canvasTop;

        /// <summary>
        /// グリッド配置時の行高さ
        /// </summary>
        [Display(Name = "Grid Height", GroupName = LayoutGroup)]
        [ViewProperty(ViewControl.Properties.IsVisibile, "IsGridElement")]
        public string GridHeight { get; set; }

        /// <summary>
        /// グリッド配置時の列幅
        /// </summary>
        [Display(Name = "Grid Width", GroupName = LayoutGroup)]
        [ViewProperty(ViewControl.Properties.IsVisibile, "IsGridElement")]
        public string GridWidth { get; set; }

        /// <summary>
        /// パネル配置時の垂直配置位置
        /// </summary>
        [Display(Name = "Vertical Align", Description = "Vertical Alignment", GroupName = LayoutGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "VerticalAlignmentList")]
        public LayoutVerticalAlignment? VerticalAlignment { get; set; }

        /// <summary>
        /// パネル配置時の水平配置位置
        /// </summary>
        [Display(Name = "Horizontal Align", Description = "Horizontal Alignment", GroupName = LayoutGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "HorizontalAlignmentList")]
        public LayoutHorizontalAlignment? HorizontalAlignment { get; set; }

        /// <summary>
        /// グリッドの行Span（0を指定すると最終行まで結合される）
        /// </summary>
        [Display(Name = "Grid RowSpan", GroupName = LayoutGroup)]
        [ViewProperty(ViewControl.Properties.IsVisibile, "IsGridElement")]
        public int RowSpan { get; set; }

        /// <summary>
        /// グリッドの列Span（0を指定すると最終列まで結合される）
        /// </summary>
        [Display(Name = "Grid ColumnSpan", GroupName = LayoutGroup)]
        [ViewProperty(ViewControl.Properties.IsVisibile, "IsGridElement")]
        public int ColumnSpan { get; set; }

        /// <summary>
        /// 有効／無効の設定（バインドするパス）
        /// </summary>
        [Display(GroupName = GeneralGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "BindablePathList")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public virtual string IsEnabled { get; set; }

        /// <summary>
        /// 表示／非表示の設定（バインドするパス）
        /// </summary>
        [Display(GroupName = GeneralGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "BindablePathList")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public virtual string IsVisibile { get; set; }

        /// <summary>
        /// フォントサイズ
        /// </summary>
        [Display(GroupName = StyleGroup)]
        public double? FontSize { get; set; }

        /// <summary>
        /// 前景色
        /// </summary>
        [Display(GroupName = StyleGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "ColorList")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public string Foreground { get; set; }

        /// <summary>
        /// 背景色
        /// </summary>
        [Display(GroupName = StyleGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "ColorList")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public string Background { get; set; }


        [XmlIgnore]
        [Display(Name = "", GroupName = LayoutGroup)]
        [View(ViewControlType.Hyperlink)]
        [ViewProperty(HyperlinkViewControl.Properties.Command, "FitVerticalAlignmentCommand")]
        public string FitVerticalAlignmentLink { get { return "Fit Vertical"; } }

        [XmlIgnore]
        [Browsable(false)]
        public ICommand FitVerticalAlignmentCommand { get { return CreateCommand(FitVerticalAlignment); } }
        private void FitVerticalAlignment()
        {
            this.GridHeight = "*";
            this.Height = null;
            this.VerticalAlignment = LayoutVerticalAlignment.Stretch;
            OnPropertyChanged(null);
        }

 
        #endregion

        #region ShouldSerialize

        public virtual bool ShouldSerializeWidth() { return Width.HasValue; }
        public virtual bool ShouldSerializeHeight() { return Height.HasValue; }
        public virtual bool ShouldSerializeCanvasLeft() { return CheckParentType(ViewControlType.Canvas); }
        public virtual bool ShouldSerializeCanvasTop() { return CheckParentType(ViewControlType.Canvas); }
        public virtual bool ShouldSerializeGridHeight() { return CheckParentType(ViewControlType.Grid); }
        public virtual bool ShouldSerializeGridWidth() { return CheckParentType(ViewControlType.Grid); }
        public virtual bool ShouldSerializeRowSpan() { return CheckParentType(ViewControlType.Grid); }
        public virtual bool ShouldSerializeColumnSpan() { return CheckParentType(ViewControlType.Grid); }
        public virtual bool ShouldSerializeXmlAdditionalProperty() { return XmlAdditionalProperty != null && XmlAdditionalProperty.Count() > 0; }
        public virtual bool ShouldSerializeWindowSettings() { return IsRootElement; }
        public virtual bool ShouldSerializeHorizontalAlignment() { return HorizontalAlignment.HasValue; }
        public virtual bool ShouldSerializeVerticalAlignment() { return VerticalAlignment.HasValue; }
        public virtual bool ShouldSerializeFontSize() { return FontSize.HasValue; }

        protected bool CheckParentType(ViewControlType parent)
        {
            if (this.Item.Parent == null) return false;
            return this.Item.Parent.ControlType == parent;
        }
        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ViewControl()
        {
            RowSpan = 1;
            ColumnSpan = 1;

        }

        internal override void CopyFrom(ViewElement source)
        {
            var viewCtrl = source as ViewControl;
            if (viewCtrl == null) return;
            if (viewCtrl.CanvasLeft.HasValue) this.CanvasLeft = viewCtrl.CanvasLeft;
            if (viewCtrl.CanvasTop.HasValue) this.CanvasTop = viewCtrl.CanvasTop;
            if (!string.IsNullOrEmpty(GridHeight)) this.GridHeight = viewCtrl.GridHeight;
            if (!string.IsNullOrEmpty(GridWidth)) this.GridWidth = viewCtrl.GridWidth;
            if (viewCtrl.Height.HasValue) this.Height = viewCtrl.Height;
            if (viewCtrl.Width.HasValue) this.Width = viewCtrl.Width;
            this.IsEnabled = viewCtrl.IsEnabled;
            this.IsVisibile = viewCtrl.IsVisibile;
            if (viewCtrl.VerticalAlignment.HasValue) this.VerticalAlignment = viewCtrl.VerticalAlignment;
            if (viewCtrl.HorizontalAlignment.HasValue) this.HorizontalAlignment = viewCtrl.HorizontalAlignment;
            this.RowSpan = viewCtrl.RowSpan;
            this.ColumnSpan = viewCtrl.ColumnSpan;
            this.FontSize = viewCtrl.FontSize;
            this.Foreground = viewCtrl.Foreground;
            this.Background = viewCtrl.Background;
        }

        /// <summary>
        /// Viewコントロールの共通プロパティを設定する
        /// </summary>
        /// <param name="node"></param>
        protected override void ApplyBaseProperty(XamlNode node)
        {
            base.ApplyBaseProperty(node);
            if (!string.IsNullOrEmpty(IsEnabled))
            {
                if (IsEnabled.ToLower() == "false")
                {
                    node.SetAttribute("IsEnabled", "false");
                }
                else
                {
                    SetBindingAttribute(node, "IsEnabled", IsEnabled, true);
                }
            }
            if (!string.IsNullOrEmpty(IsVisibile)) SetBindingAttribute(node, "Visibility", IsVisibile + ", Converter={StaticResource BooleanToVisibilityConverter}", true);

            var w = GetItemWidth(this);
            if (w.HasValue) node.SetAttribute("Width", w.ToString());
            var h = GetItemHeight(this);
            if (h.HasValue) node.SetAttribute("Height", h.ToString());
        }

        protected virtual double? GetFontSize()
        {
            if (FontSize.HasValue) return FontSize;
            if (this.Item.Parent != null) return this.Item.Parent.Control.GetFontSize();
            return null;
        }

        protected virtual string GetForeground()
        {
            if (!string.IsNullOrEmpty(Foreground)) return Foreground;
            if (this.Item.Parent != null) return this.Item.Parent.Control.GetForeground();
            return null;
        }

        protected virtual string GetBackground()
        {
            if (!string.IsNullOrEmpty(Background)) return Background;
            if (this.Item.Parent != null) return this.Item.Parent.Control.GetBackground();
            return null;
        }

#if !SILVERLIGHT
        /// <summary>
        /// スタイルの作成
        /// </summary>
        /// <param name="node"></param>
        /// <param name="targetType"></param>
        /// <returns></returns>
        protected XamlNode CreateStyle(XamlNode node, string targetType)
        {
            bool created = false;

            var style = node.CreateElement("Style");
            style.SetAttribute("TargetType", "{x:Type " + targetType + "}");
            var fontSize = GetFontSize();
            if (fontSize.HasValue)
            {
                created = true;
                var setter = style.AddElement("Setter");
                setter.SetAttribute("Property", "FontSize");
                setter.SetAttribute("Value", fontSize.ToString());
            }
            var fore = GetForeground();
            if (!string.IsNullOrEmpty(fore))
            {
                created = true;
                var setter = style.AddElement("Setter");
                setter.SetAttribute("Property", "Foreground");
                setter.SetAttribute("Value", fore);
            }
            var back = GetBackground();
            if (!string.IsNullOrEmpty(back))
            {
                created = true;
                var setter = style.AddElement("Setter");
                setter.SetAttribute("Property", "Background");
                setter.SetAttribute("Value", back);
            }
            return created ? style : null;
        }
#endif
        /// <summary>
        /// ビヘイビアの追加
        /// </summary>
        /// <param name="node"></param>
        /// <param name="behaviorName"></param>
        /// <param name="command"></param>
        protected void AddBehavior(XamlNode node, string behaviorName, string command)
        {
#if !SILVERLIGHT
            node.SetAttribute("vg:" + behaviorName + ".Command", "clr-namespace:ViewMaker.Core.Wpf;assembly=ViewMaker.Core", "{Binding Path=" + command + ", Mode=OneWay}");
#else
            AddGeneralBehavior(node, behaviorName, "vg:Command=\"{Binding Path=" + command + ", Mode=OneWay}\"");
#endif
        }

#if SILVERLIGHT
        protected void AddGeneralBehavior(XamlNode node, string behaviorName, string statement)
        {
            var behaviors = node.ChildElements.FirstOrDefault(x => x.Name == "Interaction.Behaviors");
            if (behaviors == null)
            {
                behaviors = node.CreateElement("i", "http://schemas.microsoft.com/expression/2010/interactivity", "Interaction.Behaviors");
                node.AppendChild(behaviors);
            }
            var behavior = node.ParseElement("<vg:" + behaviorName + " " +statement
               + " xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\""
               + " xmlns:vg=\"clr-namespace:ViewMaker.Core.Silverlight;assembly=SilverlightViewMaker.Core\" />");
            behaviors.AppendChild(behavior);
        }
#endif
        protected void StreachAlign()
        {
            VerticalAlignment = LayoutVerticalAlignment.Stretch;
            HorizontalAlignment = LayoutHorizontalAlignment.Stretch;
            Height = null;
            ColumnSpan = 0;
            GridHeight = "*";
        }
 
        #region IItemPropProvider Members

        public virtual int? GetItemWidth(ViewControl ctrl)
        {
            if (ctrl.Width.HasValue) return ctrl.Width;
            if (!ctrl.CanOverrideWidth) return null;
            if (this.Item.Parent != null)
            {
                var provider = this.Item.Parent.Element as IItemPropProvider;
                if (provider != null) return provider.GetItemWidth(ctrl);

            }
            return null;
        }

        public virtual int? GetItemHeight(ViewControl ctrl)
        {
            if (ctrl.Height.HasValue) return ctrl.Height;
            if (!ctrl.CanOverrideHeight) return null;
            if (this.Item.Parent != null)
            {
                var provider = this.Item.Parent.Element as IItemPropProvider;
                if (provider != null) return provider.GetItemHeight(ctrl);

            }
            return null;
        }

        //public virtual string GetItemMargin(ViewControl ctrl)
        //{
        //    if (this.Item.Parent != null)
        //    {
        //        var provider = this.Item.Parent.Control as IItemPropProvider;
        //        if (provider != null) return provider.GetItemMargin(ctrl);
        //    }
        //    return null;
        //}

        //public virtual LayoutHorizontalAlignment? GetHorizontalAlignment(ViewControl ctrl)
        //{
        //    return HorizontalAlignment;
        //}

        //public virtual LayoutVerticalAlignment? GetVerticalAlignment(ViewControl ctrl)
        //{
        //    return VerticalAlignment;
        //}

        #endregion
    }



}
